React 留言板實作


Posted by chihyu on 2021-01-25

留言板

建立檔案基本結構

  1. 在 src 資料夾裡面建立一個 components 資料夾
  2. 在 components 資料夾裡面建立一個專案資料夾 ex. App
  3. App 資料夾裡面的檔案:App.js、App.test.js、index.js
  4. 在 index.js 把 App.js export 出去
    // 就寫這兩行
    import App from "./App";
    export default App;
    
  5. 在 src 資料夾裡面的 index.js 引入 App.js 並 render 出來
    import React from "react";
    import ReactDOM from "react-dom";
    import App from "./components/App";
    // ReactDOM.render(<App />, document.getElementById("root"));
    ReactDOM.render(<App />, document.getElementById("root"));
    

切版

  1. 引入 styled-component
    import styled from "styled-components";
    
  2. 在 function App() 把留言板主要架構的 component 寫入
  3. 幫 component 加上 style
  4. 把留言內容寫一個 function component,把會變動的內容用參數帶入
    function Message({ author, time, children }) {
    return () 
    }
    

串接資料

  1. 宣告留言的 state
    // 先引入
    import React, { useState } from "react";
    
    // 在 function App 裡面宣告
    const [messages, setMessages] = useState([])
    
  2. 使用 useEffect (因為是要在 render 完拿資料)
    // 先引入
    import React, { useState, useEffect } from "react";
    
    // 在 function App 裡面使用,因為只要執行一次,所以後面傳空陣列因
    useEffect(() => {
    }, [])
    
  3. 在 useEffect 裡面串接 api
    useEffect(() => {
     fetch(API_ENDPOINT) // api 
       .then((res) => res.json()) 
       .then((data) => {
         setMessages(data) // setter 將資料帶入
       })
       .catch(err => { // 錯誤處理
         setApiError(err.message)
       })
    }, [])
    
  4. 把資料帶入留言板
    <MessageList>
    {messages.map(message => (
     <Message key={message.id} author={message.nickname} time={message.createdAt}>
       {message.body}
     </Message>
    ))}
    </MessageList>
    
  5. 做錯誤處理
    api 錯誤,沒找到資料時:
    // 使用 useState
    const [messageApiError, setMessageApiError] = useState(null);
    {messageApiError && (
    <ErrorMessage>
     Something went wrong.{messageApiError.toString()}
    </ErrorMessage>
    )}
    
    沒有留言時:
    {messages.length === 0 && <div>No Message</div>}
    
  6. 使用 propTypes 檢查 prop 的型態是不是正確的
    // 引入
    import PropTypes from 'prop-types';
    
    // 把參數帶入 propTypes
    Message.propTypes = {
    author: PropTypes.string,
    time: PropTypes.string,
    children: PropTypes.node
    }
    

實作功能

  1. 實作 textarea 的功能,做成 control component,用 useState
    // textarea 的 value 使用 useState
    const [value, setValue] = useState();
    // value 的參數帶 value,onChange 的參數帶一個 function 
    <MessageTextArea value={value} onChange={handleTextareaChange} rows={5} />
    // function 裡面設置 setValue (setter)
    const handleTextareaChange = e => {
    setValue(e.target.value)
    }
    
  2. 實作送出表單功能
    // onSubmit 的參數帶一個 function 
    <MessageForm onSubmit={handleFormSubmit}>
    // function 裡面先實作 submit 功能,用 post 把資料送出
    const handleFormSubmit = e => {
    e.preventDefault(); // 先防止預設事件
    fetch('https://student-json-api.lidemy.me/comments', {
     method: 'POST',
     headers: {
       'content-type': 'application/json'
     },
     body: JSON.stringify({
       nickname: 'sun',
       body: value
     })
    })
    .then(res => res.json())
    .then(data => {
     fetchMessages() // submit 後再 call api,取得最新資料 
    })
    }
    
    // 因為重複使用到 call api,要把 call api 的部分另外宣告出來
    const fetchMessages = () => {
    return fetch(API_ENDPOINT)
     .then((res) => res.json())
     .then((data) => {
       setMessages(data)
     })
     .catch(err => {
       setApiError(err.message)
     })
    }
    
  3. 送出空白留言的錯誤處理
    // 使用 useState
    const [postMessageError, setPostMessageError] = useState();
    // 如果回傳的資料不 ok 就回傳 api 的訊息
    if (data.ok === 0) {
    setPostMessageError(data.message)
    return;
    }
    // 寫在 submit 下面,把回傳的訊息帶入
    <SubmitButton>送出留言</SubmitButton>
    {postMessageError && <ErrorMessage>{postMessageError}</ErrorMessage>}
    
    如果點回 textarea 錯誤處理的訊息就消失
    // 在 textarea 加上
    onFocus={handleTextareaFocus} 
    // 當 textarea 被點擊就把錯誤處理改成 null
    const handleTextareaFocus = e => {
    setPostMessageError(null);
    }
    
  4. 預防一直點擊按鈕,確認是不是在送出留言的 state
    // 使用 useState
    const [isLoadingPostMessage, setIsLoadingPostMessage] = useState(false);
    // 如果是 true 就不管他,不然就在發 api 之前設成 true
    if (isLoadingPostMessage) {
     return;
    }
    setIsLoadingPostMessage(true);
    // 在結果回來之後設成 false
    setIsLoadingPostMessage(false)
    
  5. 在 page 裡面設置 Loading 狀態
    // 如果正在 Loading 就顯示 Loading
    {isLoadingPostMessage && <Loading>Loading...</Loading>}
    

#Web #React #message-board







Related Posts

Chrome devtools extension 實作介紹

Chrome devtools extension 實作介紹

Understanding Global Conflic and Cooperration

Understanding Global Conflic and Cooperration

使用 Gazebo 模擬器控制機器人建立 2D 地圖

使用 Gazebo 模擬器控制機器人建立 2D 地圖


Comments